package com.commerce.product.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;

import java.time.Duration;
import java.util.concurrent.Executor;

/**
 * 性能优化配置类
 */
@Configuration
@EnableAsync
@EnableCaching
public class PerformanceConfig {

    /**
     * 异步任务线程池配置
     */
    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        
        // 核心线程数
        executor.setCorePoolSize(10);
        
        // 最大线程数
        executor.setMaxPoolSize(50);
        
        // 队列容量
        executor.setQueueCapacity(1000);
        
        // 线程空闲时间
        executor.setKeepAliveSeconds(60);
        
        // 线程名前缀
        executor.setThreadNamePrefix("FlashSale-Async-");
        
        // 拒绝策略：由调用线程处理
        executor.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy());
        
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        
        // 等待时间
        executor.setAwaitTerminationSeconds(60);
        
        executor.initialize();
        return executor;
    }

    /**
     * 秒杀专用线程池
     */
    @Bean("flashSaleExecutor")
    public Executor flashSaleExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        
        // 秒杀场景需要更多线程处理高并发
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(100);
        executor.setQueueCapacity(2000);
        executor.setKeepAliveSeconds(30);
        executor.setThreadNamePrefix("FlashSale-Core-");
        
        // 快速失败策略
        executor.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.AbortPolicy());
        
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(30);
        
        executor.initialize();
        return executor;
    }

    /**
     * Redis缓存管理器配置
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 配置序列化
        RedisSerializationContext.SerializationPair<String> stringSerializationPair = 
            RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer());
        
        RedisSerializationContext.SerializationPair<Object> jsonSerializationPair = 
            RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer());

        // 配置缓存
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(10))                    // 默认缓存10分钟
            .serializeKeysWith(stringSerializationPair)          // Key序列化
            .serializeValuesWith(jsonSerializationPair)          // Value序列化
            .disableCachingNullValues()                          // 不缓存空值
            .prefixCacheNameWith("flash-sale:");                 // 缓存前缀

        return RedisCacheManager.builder(redisConnectionFactory)
            .cacheDefaults(config)
            .build();
    }

    /**
     * 线程池配置属性
     */
    @ConfigurationProperties(prefix = "thread-pool")
    public static class ThreadPoolProperties {
        private int corePoolSize = 10;
        private int maxPoolSize = 50;
        private int queueCapacity = 1000;
        private int keepAliveSeconds = 60;
        private String threadNamePrefix = "FlashSale-";

        // Getters and Setters
        public int getCorePoolSize() {
            return corePoolSize;
        }

        public void setCorePoolSize(int corePoolSize) {
            this.corePoolSize = corePoolSize;
        }

        public int getMaxPoolSize() {
            return maxPoolSize;
        }

        public void setMaxPoolSize(int maxPoolSize) {
            this.maxPoolSize = maxPoolSize;
        }

        public int getQueueCapacity() {
            return queueCapacity;
        }

        public void setQueueCapacity(int queueCapacity) {
            this.queueCapacity = queueCapacity;
        }

        public int getKeepAliveSeconds() {
            return keepAliveSeconds;
        }

        public void setKeepAliveSeconds(int keepAliveSeconds) {
            this.keepAliveSeconds = keepAliveSeconds;
        }

        public String getThreadNamePrefix() {
            return threadNamePrefix;
        }

        public void setThreadNamePrefix(String threadNamePrefix) {
            this.threadNamePrefix = threadNamePrefix;
        }
    }

    /**
     * 秒杀系统配置属性
     */
    @ConfigurationProperties(prefix = "flash-sale")
    public static class FlashSaleProperties {
        private StockConfig stock = new StockConfig();
        private RateLimitConfig rateLimit = new RateLimitConfig();
        private AntiSpamConfig antiSpam = new AntiSpamConfig();
        private MqConfig mq = new MqConfig();

        // 库存配置
        public static class StockConfig {
            private long preloadInterval = 300000;    // 5分钟
            private long syncInterval = 1800000;      // 30分钟
            private int batchSize = 100;

            // Getters and Setters
            public long getPreloadInterval() { return preloadInterval; }
            public void setPreloadInterval(long preloadInterval) { this.preloadInterval = preloadInterval; }
            public long getSyncInterval() { return syncInterval; }
            public void setSyncInterval(long syncInterval) { this.syncInterval = syncInterval; }
            public int getBatchSize() { return batchSize; }
            public void setBatchSize(int batchSize) { this.batchSize = batchSize; }
        }

        // 限流配置
        public static class RateLimitConfig {
            private int ipLimit = 100;
            private int userLimit = 10;
            private int windowSize = 60;

            // Getters and Setters
            public int getIpLimit() { return ipLimit; }
            public void setIpLimit(int ipLimit) { this.ipLimit = ipLimit; }
            public int getUserLimit() { return userLimit; }
            public void setUserLimit(int userLimit) { this.userLimit = userLimit; }
            public int getWindowSize() { return windowSize; }
            public void setWindowSize(int windowSize) { this.windowSize = windowSize; }
        }

        // 防刷配置
        public static class AntiSpamConfig {
            private int maxRequestsPerMinute = 20;
            private long banDuration = 3600;
            private double suspiciousThreshold = 0.8;

            // Getters and Setters
            public int getMaxRequestsPerMinute() { return maxRequestsPerMinute; }
            public void setMaxRequestsPerMinute(int maxRequestsPerMinute) { this.maxRequestsPerMinute = maxRequestsPerMinute; }
            public long getBanDuration() { return banDuration; }
            public void setBanDuration(long banDuration) { this.banDuration = banDuration; }
            public double getSuspiciousThreshold() { return suspiciousThreshold; }
            public void setSuspiciousThreshold(double suspiciousThreshold) { this.suspiciousThreshold = suspiciousThreshold; }
        }

        // 消息队列配置
        public static class MqConfig {
            private String orderQueue = "flash.sale.order";
            private String stockQueue = "flash.sale.stock";
            private String dlq = "flash.sale.dlq";
            private long ttl = 900000;

            // Getters and Setters
            public String getOrderQueue() { return orderQueue; }
            public void setOrderQueue(String orderQueue) { this.orderQueue = orderQueue; }
            public String getStockQueue() { return stockQueue; }
            public void setStockQueue(String stockQueue) { this.stockQueue = stockQueue; }
            public String getDlq() { return dlq; }
            public void setDlq(String dlq) { this.dlq = dlq; }
            public long getTtl() { return ttl; }
            public void setTtl(long ttl) { this.ttl = ttl; }
        }

        // Getters and Setters
        public StockConfig getStock() { return stock; }
        public void setStock(StockConfig stock) { this.stock = stock; }
        public RateLimitConfig getRateLimit() { return rateLimit; }
        public void setRateLimit(RateLimitConfig rateLimit) { this.rateLimit = rateLimit; }
        public AntiSpamConfig getAntiSpam() { return antiSpam; }
        public void setAntiSpam(AntiSpamConfig antiSpam) { this.antiSpam = antiSpam; }
        public MqConfig getMq() { return mq; }
        public void setMq(MqConfig mq) { this.mq = mq; }
    }
}
